Skip to content

Mitigate ED_Alloc crashes caused by disposable entity accumulation - #1188

Open
lozatto wants to merge 6 commits into
rehlds:masterfrom
lozatto:feature/garbage-collector-clean
Open

Mitigate ED_Alloc crashes caused by disposable entity accumulation#1188
lozatto wants to merge 6 commits into
rehlds:masterfrom
lozatto:feature/garbage-collector-clean

Conversation

@lozatto

@lozatto lozatto commented Sep 3, 2026

Copy link
Copy Markdown

This PR introduces an intelligent Garbage Collector to prevent the notorious ED_Alloc: no free edicts server crash.

In heavy mods like Zombie Plague or servers with high drop rates, the engine can easily hit the entity limit due to excessive dropped weapons, shields, and gibs on the ground. When that happens, the server crashes instantly.

What this does:

  • Adds a new CVAR mp_entity_gc (enabled by default) to control the system.
  • Actively monitors the current entity count in StartFrame.
  • If the server gets dangerously close to the limit (less than 100 free edicts), the GC kicks in and safely cleans up the oldest disposable entities (weaponbox, weapon_shield, and gib) to free up slots.
  • Safe: C4 bombs are explicitly protected. They will never be deleted by the GC, even if they are inside a dropped weaponbox.

This is a massive stability improvement for custom and heavily modded servers!

@Rafflesian

Rafflesian commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

I don't see the point on this, if you're having crashes with max edicts I think the issue is your mod instead of this solution.
Also I think an improvement is logging + server print if maxedicts is reached and every CREATE_ENTITY returns nullptr instead of crashing.
And you can increase the max edicts with -maxedicts param if I recall correctly (max is 2048)

@lozatto

lozatto commented Sep 3, 2026

Copy link
Copy Markdown
Author

I don't see the point on this, if you're having crashes with max edicts I think the issue is your mod instead of this solution. Also I think an improvement is logging + server print if maxedicts is reached and every CREATE_ENTITY returns nullptr instead of crashing. And you can increase the max edicts with -maxedicts param if I recall correctly (max is 2048)

I agree that a mod creating entities indefinitely should be fixed at the source, and I don't intend this GC to replace fixing entity leaks in mods.

However, I think there is still a valid purpose for having this protection in the GameDLL.

The problem with max edicts is that once the engine reaches the limit, the failure happens at allocation time. At that point, there is no opportunity for the GameDLL to recover unless it has already reclaimed some disposable entities.

This GC is intentionally proactive. It does not wait until ED_Alloc fails. It monitors entity usage with some headroom and removes only specific disposable entities (weaponbox, weapon_shield and gib) that can safely be discarded, while explicitly preserving the C4 weaponbox.

So I see this as a defensive/resource-reclamation mechanism rather than a workaround for broken mods.

I also agree with your point that this alone cannot guarantee that ED_Alloc will never happen. There is always a possible race/window between the GC pass and a subsequent entity allocation, and there may also be entity classes that the GC cannot safely remove.

Because of that, I think the ideal solution is actually two layers:

  1. Proactively reclaim disposable entities before the limit is reached.
  2. Make entity allocation fail gracefully (nullptr) when no edict is available instead of crashing the server.

The first layer reduces the probability of reaching the limit, while the second layer is the actual last line of defense.

Regarding -maxedicts, I agree that increasing the limit provides more headroom, but it doesn't solve the underlying problem if disposable entities continue accumulating. It only moves the point at which exhaustion occurs.

I also agree that logging when entity usage reaches the critical threshold would be useful. In fact, I think the GC could log the current entity count, max edicts, how many entities were reclaimed, and potentially which classes are consuming the edicts. That would make this useful not only as a safeguard but also as a diagnostic tool.

So I don't intend to claim that this prevents every possible ED_Alloc. The more precise goal of the patch is to mitigate entity exhaustion caused by accumulated disposable entities and provide the engine with some recovery headroom before allocation reaches the hard limit.

If you think the allocation failure handling should also be addressed in the same area, I'm open to extending the patch in that direction.

@lozatto lozatto changed the title feat: Add Garbage Collector to prevent ED_Alloc crashes Mitigate ED_Alloc crashes caused by disposable entity accumulation Sep 3, 2026
@lozatto

lozatto commented Sep 3, 2026

Copy link
Copy Markdown
Author

I don't see the point on this, if you're having crashes with max edicts I think the issue is your mod instead of this solution. Also I think an improvement is logging + server print if maxedicts is reached and every CREATE_ENTITY returns nullptr instead of crashing. And you can increase the max edicts with -maxedicts param if I recall correctly (max is 2048)

There is also another scenario worth considering: reaching the edict limit does not necessarily mean that the mod is leaking entities.

For example, I can have a very aggressive Boss encounter where, during a specific attack phase, the Boss legitimately creates a large number of temporary entities at once. The server may already be close to the edict limit because of normal gameplay, and that burst can push it over the limit.

In that case, there may be no persistent entity leak to fix. The problem is simply that the server temporarily reaches the allocation limit.

This is another reason why I think proactive garbage collection has value in the GameDLL. If there are disposable entities such as old weaponbox, weapon_shield or gib entities that are no longer useful, reclaiming them before the hard limit is reached gives the server additional headroom for legitimate entity creation.

So I see two different cases:

  • A mod continuously leaks entities → the mod should be fixed.
  • A legitimate gameplay event temporarily creates a large number of entities while the server is already under pressure → having a defensive reclamation mechanism is still useful.

The GC is not intended to hide the first problem. It is intended to make the second case safer, while also reducing the impact of accumulated disposable entities.

And I agree that allocation itself should still fail gracefully if there is genuinely no edict available. That would be the final safety net.

@Rafflesian

Copy link
Copy Markdown
Contributor

My point is, I have an active server (mostly +20 users 32 at night) on some maps where bosses spawns a bunch of entities (explosives-effects) and/or children (lesser npc's) and I haven't had an issue with maxedicts error.
Your mod is sort of tower defense/zombie scenario like or something?
Cuz it's very weird you're having this, but I firmly believe that ED_Alloc should return nullptr if maxedicts is reached instead of crashing, and your issue should be transferred/reinterpreted to rehlds

@lozatto

lozatto commented Sep 4, 2026

Copy link
Copy Markdown
Author

My point is, I have an active server (mostly +20 users 32 at night) on some maps where bosses spawns a bunch of entities (explosives-effects) and/or children (lesser npc's) and I haven't had an issue with maxedicts error.
Your mod is sort of tower defense/zombie scenario like or something?
Cuz it's very weird you're having this, but I firmly believe that ED_Alloc should return nullptr if maxedicts is reached instead of crashing, and your issue should be transferred/reinterpreted to rehlds

Yeah, I agree. I think this part would make more sense to be addressed in ReHLDS, since ED_Alloc() is an engine-level allocation function.

However, I think it would still be beneficial to keep both layers of protection.

The engine could handle max_edicts exhaustion gracefully by returning nullptr instead of crashing, while ReGameDLL can still check the available edicts before attempting the allocation and validate the returned entity afterward.

So it would essentially be a double safety layer:

  1. ReGameDLL avoids making the allocation request when we already know there are no edicts available.
  2. ReHLDS still handles the allocation failure safely in case the limit is reached between the check and the actual allocation, or another code path reaches ED_Alloc() directly.

I don't see these as competing solutions. The ReHLDS change would make the engine more robust, while keeping the checks in ReGameDLL protects the mod from unexpected allocation failures.

This also covers legitimate peak-usage scenarios, such as a boss spawning several effects/projectiles/child NPCs in a short burst while the server is already close to the edict limit, without requiring us to assume that every max_edicts condition is caused by an entity leak or a bug in the mod.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants